package co.fitstart.admin.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dynamic;
import com.demo2do.core.support.Page;
import com.demo2do.core.utils.CollectionUtils;
import com.demo2do.core.utils.DateUtils;

import co.fitstart.admin.dao.InbodyRecordDao;
import co.fitstart.admin.dao.ReportDao;
import co.fitstart.admin.dao.StudentDao;
import co.fitstart.admin.dao.UserDao;
import co.fitstart.admin.entity.report.BodyReport;
import co.fitstart.admin.entity.search.OfflineStudentSearch;
import co.fitstart.admin.entity.search.OnlineStudentSearch;
import co.fitstart.admin.entity.search.SiteStudentSearch;
import co.fitstart.admin.entity.security.Login;
import co.fitstart.admin.service.StudentService;
import co.fitstart.entity.course.CourseType;
import co.fitstart.entity.course.round.CourseRound;
import co.fitstart.entity.course.round.RoundStatus;
import co.fitstart.entity.course.schedule.CourseSchedule;
import co.fitstart.entity.finance.StudentExportRecord;
import co.fitstart.entity.site.Site;
import co.fitstart.entity.user.Student;
import co.fitstart.entity.user.StudentTargetData;
import co.fitstart.entity.user.User;
import co.fitstart.entity.user.UserTargetData;
import co.fitstart.entity.user.bwh.BwhRecord;
import co.fitstart.entity.user.inbody.InbodyRecord;
import co.fitstart.entity.user.investigation.FitInvestigation;
import co.fitstart.entity.user.investigation.HealthInvestigation;
import co.fitstart.entity.user.investigation.ParticipateInvestigation;

/**
 * 
 * @author mohanlan
 *
 */
@Service("studentService")
public class StudentServiceImpl extends DataServiceImpl<Student> implements StudentService {

    @Autowired
    private GenericDaoSupport genericDaoSupport;

    @Dynamic
    private UserDao userDao;

    @Dynamic
    private InbodyRecordDao inbodyRecordDao;

    @Dynamic
    private StudentDao studentDao;

    @Dynamic
    private ReportDao reportDao;

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#list(com.demo2do.core.support.
     * Page)
     */
    public List<Student> list(boolean export, Page page) {
        Date date = DateUtils.parseDate("2017-12-01 00:00:00", "yyyy-MM-dd HH:mm:ss");
        List<Student> result = studentDao.list(export, date, page.getBeginIndex(), page.getMaxResultRecords());

        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see co.fitstart.admin.service.StudentService#listUnExportStudent()
     */
    public List<Student> listUnExportStudent() {
        return studentDao.list();
    }

    /*
     * (non-Javadoc)
     * 
     * @see co.fitstart.admin.service.StudentService#list(java.lang.String,
     * com.demo2do.core.support.Page)
     */
    public List<Student> list(String type, Page page) {
        List<Student> result = new ArrayList<Student>();

        if (StringUtils.equals(type, "online")) {
            result = studentDao.listOnlineStudent(page.getBeginIndex(), page.getMaxResultRecords());
        } else {
            result = studentDao.listOfflineStudent(page.getBeginIndex(), page.getMaxResultRecords());
        }

        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#list(co.fitstart.entity.site.
     * Site, com.demo2do.core.support.Page)
     */
    public List<Student> list(Site site, Page page) {
        List<Student> result = studentDao.listOfflineStudent(
                new CourseType[] { CourseType.INDIVIDUAL,CourseType.SPECIAL,CourseType.POSTURE, CourseType.GROUP, CourseType.YEAR }, site,
                page.getBeginIndex(), page.getMaxResultRecords());

        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.StudentService#list(java.util.List, com.demo2do.core.support.Page)
     */
    public List<Student> list(List<Site> sites, Page page) {
        List<Student> result = studentDao.listOfflineStudent(
                new CourseType[] { CourseType.INDIVIDUAL,CourseType.SPECIAL,CourseType.POSTURE, CourseType.GROUP, CourseType.YEAR }, sites,
                page.getBeginIndex(), page.getMaxResultRecords());

        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#onlineStudentSearch(co.fitstart.
     * admin.entity.search.OnlineStudentSearch, com.demo2do.core.support.Page)
     */
    @SuppressWarnings("unchecked")
    public List<Student> onlineStudentSearch(OnlineStudentSearch studentSearch, Page page) {
        List<Student> result = genericDaoSupport.searchForList(studentSearch.buildSentenceTemplate(),
                studentSearch.buildParameters(), page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#offlineStudentSearch(co.fitstart
     * .admin.entity.search.OfflineStudentSearch, com.demo2do.core.support.Page)
     */
    @SuppressWarnings("unchecked")
    public List<Student> offlineStudentSearch(OfflineStudentSearch studentSearch, Page page) {
        List<Student> result = genericDaoSupport.searchForList(studentSearch.buildSentenceTemplate(),
                studentSearch.buildParameters(), page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#search(co.fitstart.admin.entity.
     * search.SiteStudentSearch, com.demo2do.core.support.Page)
     */
    @SuppressWarnings("unchecked")
    public List<Student> search(SiteStudentSearch siteStudentSearch, Page page) {
        List<Student> result = genericDaoSupport.searchForList(siteStudentSearch.buildSentenceTemplate(),
                siteStudentSearch.buildParameters(), page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    @Override
    public Student load(String mobile) {
    	return studentDao.load(mobile);
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see co.fitstart.admin.service.StudentService#load(java.lang.String,
     * java.lang.String)
     */
    public Student load(String type, String mobile) {
        Student student = null;

        if (StringUtils.equals(type, "online")) {
            student = studentDao.loadOnlineStudent(mobile);
        } else {
            student = studentDao.loadOfflineStudent(mobile);
        }

        if (student == null) {
            throw new BusinessException("用户不存在");
        }
        return student;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#load(co.fitstart.entity.user.
     * User)
     */
    public Student load(User user) {
        return studentDao.load(user);
    }

    /*
     * (non-Javadoc)
     * 
     * @see co.fitstart.admin.service.StudentService#load(java.lang.String,
     * co.fitstart.entity.site.Site)
     */
    public Student load(String mobile, Site site) {
        Student student = studentDao.loadOfflineStudent(
                new CourseType[] { CourseType.INDIVIDUAL,CourseType.SPECIAL,CourseType.POSTURE, CourseType.GROUP, CourseType.YEAR }, site, mobile);

        if (student == null) {
            throw new BusinessException("用户不存在");
        }
        return student;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.StudentService#load(java.lang.String, java.util.List)
     */
    public Student load(String mobile, List<Site> sites) {
        Student student = studentDao.loadOfflineStudent(
                new CourseType[] {CourseType.INDIVIDUAL,CourseType.SPECIAL,CourseType.POSTURE, CourseType.GROUP, CourseType.YEAR }, sites, mobile);

        if (student == null) {
            throw new BusinessException("用户不存在");
        }
        return student;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.impl.StudentViewService#listUserFitRecord(co.
     * fitstart.entity.user.User)
     */
    public List<FitInvestigation> listFitInvestigation(User user) {
        return userDao.listFitInvestigation(user);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.impl.StudentViewService#listInbodyRecord(co.
     * fitstart.entity.user.User)
     */
    public List<InbodyRecord> listInbodyRecord(User user) {
        return inbodyRecordDao.listInbodyRecord(user);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#listBwhRecord(co.fitstart.entity
     * .user.User)
     */
    public List<BwhRecord> listBwhRecord(User user) {
        return userDao.listBwhRecord(user);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#getBwhRecord(java.lang.Long)
     */
    public BwhRecord getBwhRecord(Long bwhId) {
        return genericDaoSupport.get(BwhRecord.class, bwhId);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#updateBwhRecord(co.fitstart.
     * entity.user.bwh.BwhRecord)
     */
    public void editBwhRecord(BwhRecord bwhRecord) {
        genericDaoSupport.update(bwhRecord);
    }

    /*
     * (non-Javadoc)
     * 
     * @see co.fitstart.admin.service.StudentService#listStudentTargetData(co.
     * fitstart.entity.user.User)
     */
    public List<StudentTargetData> listStudentTargetData(User user) {
        return userDao.listStudentTargetData(user);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#listUserTargetData(co.fitstart.
     * entity.user.User)
     */
    public UserTargetData listUserTargetData(User user) {
        List<UserTargetData> userTargetDatas = userDao.listUserTargetData(user);
        return userTargetDatas == null || userTargetDatas.size() == 0 ? null : userTargetDatas.get(0);
    }

    /*
     * (non-Javadoc)
     * 
     * @see co.fitstart.admin.service.StudentService#listStudentTargetData(co.
     * fitstart.entity.user.Student,
     * co.fitstart.entity.course.round.CourseRound)
     */
    public List<StudentTargetData> listStudentTargetData(Student student, CourseRound courseRound) {
        return studentDao.listStudentTargetData(student, courseRound);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.impl.StudentViewService#loadHealthInvestigation
     * (co.fitstart.entity.user.User)
     */
    public HealthInvestigation loadHealthInvestigation(User user) {
        return userDao.loadHealthInvestigation(user);
    }

    /*
     * (non-Javadoc)
     * 
     * @see co.fitstart.admin.service.impl.StudentViewService#
     * loadParticipateInvestigation(co.fitstart.entity.user.User)
     */
    public ParticipateInvestigation loadParticipateInvestigation(User user) {
        return userDao.loadParticipateInvestigation(user);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#editUserTargetData(co.fitstart.
     * entity.user.UserTargetData, co.fitstart.entity.user.User)
     */
    public void editUserTargetData(UserTargetData userTargetData, User user) {
        if (userTargetData.getId() == null) {
            userTargetData.initilization(user);
            genericDaoSupport.save(userTargetData);
        } else {
            genericDaoSupport.update(userTargetData);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#exportUserInformation(java.util.
     * Date, java.util.Date)
     */
    public List<Student> exportUserInformation(Site site, Date startTime, Date endTime) {

        // load students by parameters.
        List<Student> students = reportDao.listStudent(
                new CourseType[] { CourseType.INDIVIDUAL,CourseType.SPECIAL,CourseType.POSTURE, CourseType.GROUP, CourseType.YEAR }, site, startTime,
                endTime);

        return students;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.StudentService#exportUserInformation(java.util.List, java.util.Date, java.util.Date)
     */
    public List<Student> exportUserInformation(List<Site> sites, Date startTime, Date endTime) {
        List<Student> students = reportDao.listStudent(
                new CourseType[] { CourseType.INDIVIDUAL,CourseType.SPECIAL,CourseType.POSTURE, CourseType.GROUP, CourseType.YEAR }, sites, startTime,
                endTime);

        return students;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#exportConsumingBehavior(java.
     * util.List)
     */
    public List<CourseRound> exportConsumingBehavior(List<Student> students) {

        List<CourseRound> courseRounds = new ArrayList<CourseRound>();
        if (!students.isEmpty()) {
            courseRounds = reportDao.listCourseRound(students);
        }

        return courseRounds;

    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#exportCourseDetail(java.util.
     * Date, java.util.Date)
     */
    public List<CourseSchedule> exportCourseDetail(List<Student> students) {

        List<CourseSchedule> courseSchedules = new ArrayList<CourseSchedule>();
        if (!students.isEmpty()) {
            courseSchedules = reportDao.listCourseSchedule(students);
        }

        return courseSchedules;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#exportBodyData(java.util.Date,
     * java.util.Date)
     */
    @SuppressWarnings("unchecked")
    public List<BodyReport> exportBodyData(List<Student> students) {

        List<BodyReport> bodyReports = new ArrayList<BodyReport>();
        // find students by parameter.
        if (!students.isEmpty()) {

            List<CourseRound> courseRounds = reportDao.listRecentCourseRound(students);
            Map<String, List<CourseRound>> recentRounds = CollectionUtils.constructMapValuesFromList(courseRounds,
                    "student.id");

            List<User> users = CollectionUtils.extractPropertyList(students, "user");

            List<HealthInvestigation> healthInvestigations = reportDao.listRecentHealthInvestigation(users);
            Map<String, List<HealthInvestigation>> recentHealthInvestigations = CollectionUtils
                    .constructMapValuesFromList(healthInvestigations, "user.id");

            List<ParticipateInvestigation> participateInvestigations = reportDao
                    .listRecentParticipateInvestigation(users);
            Map<String, List<ParticipateInvestigation>> recentParticipateInvestigations = CollectionUtils
                    .constructMapValuesFromList(participateInvestigations, "user.id");

            List<FitInvestigation> fitInvestigations = reportDao.listRecentFitInvestigation(users);
            Map<String, List<FitInvestigation>> recentFitInvestigations = CollectionUtils
                    .constructMapValuesFromList(fitInvestigations, "user.id");

            List<InbodyRecord> inbodyRecords = reportDao.listInbodyRecord(users);
            Map<String, List<InbodyRecord>> recentInbodyRecords = CollectionUtils
                    .constructMapValuesFromList(inbodyRecords, "user.id");

            List<BwhRecord> bwhRecords = reportDao.listBwhRecord(users);
            Map<String, List<BwhRecord>> recentBwhRecords = CollectionUtils.constructMapValuesFromList(bwhRecords,
                    "user.id");

            for (Student student : students) {
                User user = student.getUser();

                CourseRound courseRound = MapUtils.isNotEmpty(recentRounds)
                        && recentRounds.get(student.getId().toString()) != null
                                ? recentRounds.get(student.getId().toString()).get(0) : null;
                InbodyRecord inbodyRecord = MapUtils.isNotEmpty(recentInbodyRecords)
                        && recentInbodyRecords.get(user.getId().toString()) != null
                                ? recentInbodyRecords.get(user.getId().toString()).get(0) : null;
                BwhRecord bwhRecord = MapUtils.isNotEmpty(recentBwhRecords)
                        && recentBwhRecords.get(user.getId().toString()) != null
                                ? recentBwhRecords.get(user.getId().toString()).get(0) : null;
                HealthInvestigation healthInvestigation = MapUtils.isNotEmpty(recentHealthInvestigations)
                        && recentHealthInvestigations.get(user.getId().toString()) != null
                                ? recentHealthInvestigations.get(user.getId().toString()).get(0) : null;
                ParticipateInvestigation participateInvestigation = MapUtils.isNotEmpty(recentParticipateInvestigations)
                        && recentParticipateInvestigations.get(user.getId().toString()) != null
                                ? recentParticipateInvestigations.get(user.getId().toString()).get(0) : null;
                FitInvestigation fitInvestigation = MapUtils.isNotEmpty(recentFitInvestigations)
                        && recentFitInvestigations.get(user.getId().toString()) != null
                                ? recentFitInvestigations.get(user.getId().toString()).get(0) : null;

                BodyReport bodyReport = new BodyReport(student, courseRound, healthInvestigation,
                        participateInvestigation, fitInvestigation, inbodyRecord, bwhRecord);

                bodyReports.add(bodyReport);
            }

        }

        return bodyReports;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#freezingCcourseDetails(java.util
     * .Date, java.util.Date)
     */
    public List<CourseRound> exportFreezingCourseDetails(List<Student> students) {

        // get students by parameters.
        List<CourseRound> courseRounds = new ArrayList<CourseRound>();

        // get courseRounds by students.
        if (!students.isEmpty()) {
            courseRounds = reportDao.listCourseRound(students, RoundStatus.HOLD);
        }

        return courseRounds;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#exportUserInformation(java.lang.
     * String, java.util.Date, java.util.Date)
     */
    public List<Student> exportUserInformation(String type, Date startTime, Date endTime) {
        List<Student> result = new ArrayList<Student>();

        if (StringUtils.equals(type, "online")) {
            result = reportDao.listOnlineStudent(startTime, endTime);
        } else {
            result = reportDao.listOfflineStudent(startTime, endTime);
        }

        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#editName(co.fitstart.entity.user
     * .Student)
     */
    public void editName(Student student) {
        // update student name first
        genericDaoSupport.update(student);

        // update user name
        User user = student.getUser();
        genericDaoSupport.update(user.editName(student.getName()));
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#exportArchives(java.util.List,
     * co.fitstart.admin.entity.security.Login)
     */
    public void exportArchives(List<Long> studentIds, Login login) {
        // update student's exportArchives first
        studentDao.exportArchives(studentIds);

        // create student export record
        StudentExportRecord record = new StudentExportRecord(studentIds.size(), login.getId());
        genericDaoSupport.save(record);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#listExportRecord(com.demo2do.
     * core.support.Page)
     */
    public List<StudentExportRecord> listExportRecord(Page page) {
        List<StudentExportRecord> result = studentDao.listExportRecord(page.getBeginIndex(),
                page.getMaxResultRecords());

        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.fitstart.admin.service.StudentService#createBwhRecord(co.fitstart.
     * entity.user.bwh.BwhRecord)
     */
    public void createBwhRecord(BwhRecord bwhRecord) {
        genericDaoSupport.save(bwhRecord);
    }

    public void editTarget(StudentTargetData target) {
        genericDaoSupport.update(target);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.StudentService#list(java.util.Set)
     */
    @SuppressWarnings("unchecked")
    public List<Student> list(Set<String> mobiles) {
        return genericDaoSupport.searchForList("FROM Student WHERE mobile IN ( :mobiles) AND disabled=false", "mobiles", mobiles);
    }
}
